﻿using System;
using System.Windows.Controls;
using System.Windows.Media;
using Telerik.Windows.Documents.Utilities;

namespace TestComparer
{
    class ComparisonWriter
    {
        private readonly TextblockWriter firstWriter;
        private readonly TextblockWriter secondWriter;

        public double Tolerance { get; set; }

        public Color CorrectForeground { get; set; }
        public Color CorrectBackground { get; set; }

        public Color WrongForeground { get; set; }
        public Color WrongBackground { get; set; }

        public ComparisonWriter(TextBlock first, TextBlock second)
        {
            this.firstWriter = new TextblockWriter(first);
            this.secondWriter = new TextblockWriter(second);

            this.CorrectForeground = Colors.Green;
            this.CorrectBackground = Colors.Transparent;

            this.WrongForeground = Colors.Red;
            this.WrongBackground = Colors.Yellow;

            this.Tolerance = 0;
        }

        public void WriteComparison(object first, object second, string description)
        {
            if (AlmostEquals(first, second))
            {
                this.WriteComparison(this.WriteCorrect, first, second, description);
            }
            else
            {
                this.WriteComparison(this.WriteWrong, first, second, description);
            }
        }

        private bool AlmostEquals(object first, object second)
        {
            if (first is Matrix && second is Matrix)
            {
                return AreAlmostEqual((Matrix)first, (Matrix)second);
            }

            return first.Equals(second);
        }

        private bool AreAlmostEqual(Matrix first, Matrix second)
        {
            return AreAlmostEqual(first.M11, second.M11) &&
                AreAlmostEqual(first.M12, second.M12) &&
                AreAlmostEqual(first.M21, second.M21) &&
                AreAlmostEqual(first.M22, second.M22) &&
                AreAlmostEqual(first.OffsetX, second.OffsetX) &&
                AreAlmostEqual(first.OffsetY, second.OffsetY);
        }

        private bool AreAlmostEqual(double first, double second)
        {
            return Math.Abs(first - second) <= this.Tolerance;
        }

        private void WriteComparison(Action<TextblockWriter, object> write, object first, object second, string description)
        {
            write(this.firstWriter, description);
            write(this.firstWriter, first);
            write(this.secondWriter, description);
            write(this.secondWriter, second);
        }

        private void WriteCorrect(TextblockWriter writer, object text)
        {
            writer.Foreground = this.CorrectForeground;
            writer.Background = this.CorrectBackground;

            writer.WriteLine(text);
        }

        private void WriteWrong(TextblockWriter writer, object text)
        {
            writer.Foreground = this.WrongForeground;
            writer.Background = this.WrongBackground;

            writer.WriteLine(text);
        }
    }
}
